#include <stdexcept>
#include <string>
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
#include <fstream>
#include <sstream>

// boost
#include <boost/algorithm/string/replace.hpp>
	
// my libraries
//# define DEBUG_LEVEL 9
#include <debug_func.h>
#include <ultoa.h>
#include <portable_timer.h>
#include <progress_indicator.h>
#include <stlhelper.h>
#include <print_error.h>
#include <count_lines_in_file.h>



#include "get_arg.h"

using boost::replace_first;
using std::cerr;
using std::cin;
using std::string;
using std::vector;
using std::ofstream;




int main(int argc, char* argv[])
{
	debug_func_cerr( 8 );

	t_program_args args;

	try
	{

	// don't use C streams
	std::ios::sync_with_stdio(false);

	// get command line arguments
	if (!process_command_line_options(argc, argv, args))
		return 1;

	// count lines
	std::streamsize cnt_lines = count_lines_in_file(args.file_input, '>');

	std::ifstream ifs(args.file_input.c_str());
	if (!ifs)
		throw std::runtime_error("Could not open " + args.file_input);


	unsigned target_seq_cnt_per_file = args.every;


	// really tiny file: bound by minimum number of sequences
	//      file_count	= cnt_lines / min_sequence_count
	//      seq_count   = min_sequence_count
	if (cnt_lines < args.min_file_count * args.min_sequence_count)
		target_seq_cnt_per_file = args.min_sequence_count;

	// quite small file: bound by minimum number of files
    //      file_count	= min_file_count
    //      seq_count   = lines spread over min_file_count
	else if (cnt_lines < args.every * args.min_file_count)
	{
		target_seq_cnt_per_file = cnt_lines / args.min_file_count + 1;
	}

	// for calculating padding with zeros so that indices align!
    // so perfectionist but useful for displaying and debugging
	unsigned expected_file_cnt = (cnt_lines + 1) / target_seq_cnt_per_file + 2;
	unsigned digits = ultoa(expected_file_cnt).length();

	
	unsigned cnt_files = 0;

	
	// sequences to be written in this file
	unsigned cnt_seq_to_be_written = 0;
	// total number of sequences
	unsigned cnt_total_seq = 0;
	string line;
	ofstream ofs;
	std::streamsize cnt_line = 0;
	t_progress_indicator dots(args.VERBOSE(), 1);
	while (std::getline(ifs, line))
	{
		++cnt_line;
		if (line.empty())
			continue;
		// sequence
		if (line[0] != '>')
		{
			// this is safe even though ofs may not be open
            //      because FASTA files are suppose to start with '>' !
            ofs << line << "\n";
			continue;
		}

		// Open new file and save to that if current one full
		if (!cnt_seq_to_be_written)
		{
			++dots;
			// reset to desired number of sequences per file
			cnt_seq_to_be_written = target_seq_cnt_per_file;
			if (ofs)
				ofs.close();
			string file_name = args.path;
			//string file_index = ultoa(cnt_files++);
			std::stringstream os;
			os.width(digits);
			os.fill('0');
  
			os << std::right<< cnt_files++;
			string file_index = os.str();
			
			replace_first(file_name, "[INDEX]", file_index);
			ofs.open(file_name.c_str());
			if (!ofs)
				throw std::runtime_error("Could not open the file [" + file_name + "]");
		}
		// accession line
		++cnt_total_seq;
		--cnt_seq_to_be_written;
		ofs << line << "\n";
	}
	dots.finish();

	args.VERBOSE() << "\t" << cnt_total_seq << " sequences written in\n";
	args.VERBOSE() << "\t" << cnt_files << " files.\n";

		
	}
	catch (std::exception& e)
	{
		std_print_error(args.CERR(), e.what());
		return 1;
	}
	catch(...)
	{
		return 1;
	}

	return 0;
}

